package cn.iocoder.yudao.module.shop.staff.service;

import cn.iocoder.yudao.framework.business.basic.dao.query.CoreLambdaQueryWrapper;
import cn.iocoder.yudao.framework.business.basic.pojo.vo.UserSimpleVO;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.exception.Assertions;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.api.infrastructure.user.AdminUserApiV2;
import cn.iocoder.yudao.module.api.infrastructure.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.module.api.member.user.MemberUserApi;
import cn.iocoder.yudao.module.api.shop.staff.dto.ShopStaffSaveDTO;
import cn.iocoder.yudao.module.api.shop.staff.enums.ShopStaffStatusEnum;
import cn.iocoder.yudao.module.shop.staff.dao.ShopStaffMapper;
import cn.iocoder.yudao.module.shop.staff.pojo.dto.ShopStaffPageDTO;
import cn.iocoder.yudao.module.shop.staff.pojo.po.ShopStaff;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import jakarta.annotation.Nullable;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserLastShopId;

/**
 * 核销人员 Service 实现类
 *
 * @author 山野羡民
 */
@Service
@Validated
public class ShopStaffServiceImpl implements ShopStaffService {

    @Resource
    private ShopStaffMapper shopStaffMapper;

    @Resource
    private MemberUserApi memberUserApi;
    @Resource
    private AdminUserApiV2 adminUserApiV2;

    @Override
    public Long createStaff(ShopStaffSaveDTO reqVO) {
        // 校验存在
        ShopStaff staffDO = getByMobile(getLoginUserLastShopId(), reqVO.getContactMobile());
        Assertions.isFalse(staffDO != null, "该手机号所属的店员已存在");
        UserSimpleVO memberUserRespDTO = memberUserApi.getUserByMobile(reqVO.getContactMobile());
        AdminUserRespDTO adminUserRespDTO = adminUserApiV2.getUserByMobile(reqVO.getContactMobile());
        // 插入
        ShopStaff verifyStaff = BeanUtils.toBean(reqVO, ShopStaff.class);
        verifyStaff.setShopId(getLoginUserLastShopId());
        verifyStaff.setMemberUserId(memberUserRespDTO == null ? 0 : memberUserRespDTO.getId());
        verifyStaff.setAdminUserId(adminUserRespDTO == null ? 0 : adminUserRespDTO.getId());
        shopStaffMapper.insert(verifyStaff);
        // 返回
        return verifyStaff.getId();
    }

    @Override
    public void updateStaff(ShopStaffSaveDTO reqVO) {
        // 校验存在
        ShopStaff oldObj = validateStaffExists(reqVO.getId());
        ShopStaff staffDO = getByMobile(getLoginUserLastShopId(), reqVO.getContactMobile());
        Assertions.isFalse(staffDO != null && !Objects.equals(staffDO.getId(), oldObj.getId()), "该手机号所属的店员已存在");
        // 更新
        ShopStaff updateObj = BeanUtils.toBean(reqVO, ShopStaff.class);
        UserSimpleVO memberUserRespDTO = memberUserApi.getUserByMobile(reqVO.getContactMobile());
        AdminUserRespDTO adminUserRespDTO = adminUserApiV2.getUserByMobile(reqVO.getContactMobile());
        updateObj.setMemberUserId(memberUserRespDTO == null ? 0 : memberUserRespDTO.getId());
        updateObj.setAdminUserId(adminUserRespDTO == null ? 0 : adminUserRespDTO.getId());
        shopStaffMapper.updateById(updateObj);
    }

    @Override
    public void saveStaff(ShopStaffSaveDTO dto) {
        UserSimpleVO memberUserRespDTO = memberUserApi.getUserByMobile(dto.getContactMobile());
        AdminUserRespDTO adminUserRespDTO = adminUserApiV2.getUserByMobile(dto.getContactMobile());
        ShopStaff staffDO = getByMobile(getLoginUserLastShopId(), dto.getContactMobile());
        if (staffDO == null) {
            staffDO = new ShopStaff();
            staffDO.setRoles(dto.getRoles());
            staffDO.setContactName(dto.getContactName());
            staffDO.setContactMobile(dto.getContactMobile());
            staffDO.setShopId(getLoginUserLastShopId());
            staffDO.setMemberUserId(memberUserRespDTO == null ? 0 : memberUserRespDTO.getId());
            staffDO.setAdminUserId(adminUserRespDTO == null ? 0 : adminUserRespDTO.getId());
            shopStaffMapper.insert(staffDO);
        } else {
            Set<Integer> newRoles = new HashSet<>(dto.getRoles());
            newRoles.addAll(staffDO.getRoles());
            staffDO.setRoles(newRoles.stream().toList());
            staffDO.setContactName(dto.getContactName());
            staffDO.setMemberUserId(memberUserRespDTO == null ? 0 : memberUserRespDTO.getId());
            staffDO.setAdminUserId(adminUserRespDTO == null ? 0 : adminUserRespDTO.getId());
            shopStaffMapper.updateById(staffDO);
        }
    }

    @Override
    public void deleteStaff(Long id) {
        // 校验存在
        ShopStaff staffDO = validateStaffExists(id);
        Assertions.equals(staffDO.getShopId(), getLoginUserLastShopId(), "不是自己店铺的员工");
        // 删除
        shopStaffMapper.deleteById(id);
    }

    private ShopStaff validateStaffExists(Long id) {
        ShopStaff staffDO = shopStaffMapper.selectById(id);
        Assertions.notNull(staffDO, "店员不存在");
        return staffDO;
    }

    @Override
    public ShopStaff getStaff(Long id) {
        return shopStaffMapper.selectById(id);
    }

    @Override
    public PageResult<ShopStaff> getStaffPage(ShopStaffPageDTO pageReqVO) {
        return shopStaffMapper.selectPage(pageReqVO);
    }

    @Override
    public List<ShopStaff> getByShopId(Long shopId, @Nullable Integer role) {
        return shopStaffMapper.selectByShopId(shopId, role);
    }

    @Override
    public List<ShopStaff> getByMemberUserId(Long memberUserId) {
        return shopStaffMapper.selectByMemberUserId(memberUserId);
    }

    @Override
    public ShopStaff getByMemberUserId(Long shopId, Long memberUserId) {
        return shopStaffMapper.selectByMemberUserId(shopId, memberUserId);
    }

    @Override
    public List<ShopStaff> getByAdminUserId(Long adminUserId) {
        return shopStaffMapper.selectByAdminUserId(adminUserId);
    }

    @Override
    public ShopStaff getByAdminUserId(Long shopId, Long adminUserId) {
        return shopStaffMapper.selectByAdminUserId(shopId, adminUserId);
    }

    @Override
    public ShopStaff getByMobile(Long shopId, String mobile) {
        return shopStaffMapper.selectByMobile(shopId, mobile);
    }

    @Override
    public ShopStaff getByUserId(Long userId, Integer userType, @Nullable Integer role) {
        return shopStaffMapper.selectOne(buildWrapper(userId, userType, role));
    }

    @Override
    public boolean isStaff(Long userId, Integer userType, @Nullable Integer role) {
        Long count = shopStaffMapper.selectCount(buildWrapper(userId, userType, role));
        return count != null && count > 0;
    }

    @Override
    public void updateStaffStatus(Long id, Integer status) {
        boolean expression = Objects.equals(status, ShopStaffStatusEnum.IDLE.getValue())
                             || Objects.equals(status, ShopStaffStatusEnum.BUSY.getValue())
                             || Objects.equals(status, ShopStaffStatusEnum.REST.getValue());
        Assertions.isTrue(expression, "状态值无效");
        LambdaUpdateWrapper<ShopStaff> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(ShopStaff::getId, id);
        updateWrapper.set(ShopStaff::getStatus, status);
        if (Objects.equals(status, ShopStaffStatusEnum.IDLE.getValue())) {
            updateWrapper.set(ShopStaff::getLastArrivedTime, LocalDateTime.now());
        }
        shopStaffMapper.update(updateWrapper);
    }

    private CoreLambdaQueryWrapper<ShopStaff> buildWrapper(Long userId, Integer userType, Integer role) {
        CoreLambdaQueryWrapper<ShopStaff> wrapper = new CoreLambdaQueryWrapper<>();
        if (role != null) {
            wrapper.apply("FIND_IN_SET({0}, roles) > 0", role);
        }
        if (UserTypeEnum.MEMBER.getValue().equals(userType)) {
            wrapper.eq(ShopStaff::getMemberUserId, userId);
        } else {
            wrapper.eq(ShopStaff::getAdminUserId, userId);
        }
        return wrapper;
    }

}